﻿Imports System.Linq.Expressions

Public NotInheritable Class RandomSource

    Private rnd As New Random()

    Public Function GetValue() As Double
        Return rnd.NextDouble()
    End Function

End Class

Public Class RandomValue


    Protected Generator As Expression
    Protected Parameters As IEnumerable(Of ParameterExpression)

    Protected Method As Func(Of Double(), Double)


    Public Overridable ReadOnly Property Value As Double
        Get

        End Get
    End Property

    Public Function Compute(ByVal ParamArray params() As Double) As Object
        If Method Is Nothing Then
            Dim tmp = Expression.Parameter(GetType(Double()))
            Dim ass = Parameters.Select( _
                  Function(e, i)
                      Return Expression.Assign( _
                                    e, _
                                    Expression.ArrayAccess( _
                                        tmp, _
                                        Expression.Constant(i)))
                  End Function)

            Dim body = New List(Of Expression)()
            body.AddRange(ass)
            body.Add(ToDouble(Generator))
            Dim block As BlockExpression = Expression.Block(Parameters, body)

            Method = Expression.Lambda(Of Func(Of Double(), Double))( _
               block, _
               tmp).Compile()

        End If
        Dim args(Parameters.Count() - 1) As Double
        Array.Copy(params, args, Math.Min(args.Length, params.Length))
        Return Method(args)
    End Function

    Public Sub New(ByVal other As RandomValue)
        Dim var = Expression.Variable(other.Generator.Type)
        Generator = _
            Expression.Block( _
                var, _
                Expression.Assign(var, other.Generator), _
                var)

        Parameters = other.Parameters.ToArray()
    End Sub
    Public Sub New()
        'Dim param = Expression.Parameter(GetType(RandomSource))
        'Parameters = New ParameterExpression() {param}
        'Generator = Expression.Call(param, "GetValue", Nothing)
        Dim param = Expression.Parameter(GetType(Double))
        Parameters = New ParameterExpression() {param}
        Generator = param 'Expression.Call(param, "GetValue", Nothing)
    End Sub
    Public Sub New(ByVal name As String)
        'Dim param = Expression.Parameter(GetType(RandomSource))
        'Parameters = New ParameterExpression() {param}
        'Generator = Expression.Call(param, "GetValue", Nothing)
        Dim param = Expression.Variable(GetType(Double), name)
        Parameters = New ParameterExpression() {param}
        Generator = param 'Expression.Call(param, "GetValue", Nothing)
    End Sub
    Private Sub New(ByVal createdefault As Boolean)
        If createdefault Then
            Dim param = Expression.Parameter(GetType(Double))
            Parameters = New ParameterExpression() {param}
            Generator = param 'Expression.Call(param, "GetValue", Nothing)
        End If
    End Sub

    Public Shared Widening Operator CType(ByVal src As RandomSource) As RandomValue
        Dim result As New RandomValue()
        ' result.Generator=Expression.Call(
    End Operator

    Public Shared Operator +(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Add(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator
    Public Shared Operator -(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Subtract(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator
    Public Shared Operator *(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Multiply(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator
    Public Shared Operator /(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Divide(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator

    Public Shared Operator >(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.GreaterThan(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator
    Public Shared Operator >=(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.GreaterThanOrEqual(ToDouble(left.Generator), ToDouble(right.Generator))

        Return result
    End Operator
    Public Shared Operator <(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.LessThan(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator
    Public Shared Operator <=(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.LessThanOrEqual(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator

    Public Shared Operator =(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        If left.Generator.Type Is right.Generator.Type Then
            result.Generator = Expression.Equal(left.Generator, right.Generator)
        Else
            If left.Generator.Type Is GetType(Double) Then
                result.Generator = Expression.Equal(left.Generator, ToDouble(right.Generator))
            Else
                result.Generator = Expression.Equal(left.Generator, ToBoolean(right.Generator))
            End If
        End If
        Return result
    End Operator
    Public Shared Operator <>(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        If left.Generator.Type Is right.Generator.Type Then
            result.Generator = Expression.NotEqual(left.Generator, right.Generator)
        Else
            If left.Generator.Type Is GetType(Double) Then
                result.Generator = Expression.NotEqual(left.Generator, ToDouble(right.Generator))
            Else
                result.Generator = Expression.NotEqual(left.Generator, ToBoolean(right.Generator))
            End If
        End If
        Return result
    End Operator

    Public Shared Operator -(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Negate(ToDouble(left.Generator))
        Return result
    End Operator
    Public Shared Operator Not(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Not(ToBoolean(left.Generator))
        Return result
    End Operator

    Public Shared Operator And(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.And(ToBoolean(left.Generator), ToBoolean(right.Generator))
        Return result
    End Operator
    Public Shared Operator Or(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Or(ToBoolean(left.Generator), ToBoolean(right.Generator))
        Return result
    End Operator
    Public Shared Operator Mod(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Call( _
            GetType(Math), _
             "IEEERemainder", _
             Nothing, _
         ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator
    Public Shared Operator ^(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Power(ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Operator

    Public Shared Function Log(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Log", _
             Nothing, _
          ToDouble(left.Generator))

        Return result
    End Function
    Public Shared Function Exp(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Exp", _
             Nothing, _
         ToDouble(left.Generator))

        Return result
    End Function
    Public Shared Function Log(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Log", _
             Nothing, _
             ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Function

    Public Shared Function Abs(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Abs", _
             Nothing, _
         ToDouble(left.Generator))

        Return result
    End Function
    Public Shared Function Ceiling(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Ceiling", _
             Nothing, _
          ToDouble(left.Generator))

        Return result
    End Function
    Public Shared Function Floor(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Floor", _
             Nothing, _
        ToDouble(left.Generator))

        Return result
    End Function
    Public Shared Function Sign(ByVal left As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Sign", _
             Nothing, _
            ToDouble(left.Generator))

        Return result
    End Function

    Public Shared Function Max(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Max", _
             Nothing, _
           ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Function
    Public Shared Function Max(ByVal ParamArray left() As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = (From r In left From p In r.Parameters Select p Distinct).ToArray()

        result.Generator = Expression.Call( _
           GetType(Enumerable), _
           "Max", _
           New Type() {GetType(Double)}, _
           Expression.NewArrayInit( _
              GetType(Double), _
              left.Select(Function(e) e.Generator)))

        Return result
    End Function
    Public Shared Function Min(ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(left.Parameters, right.Parameters)
        result.Generator = Expression.Call( _
            GetType(Math), _
             "Min", _
             Nothing, _
           ToDouble(left.Generator), ToDouble(right.Generator))
        Return result
    End Function
    Public Shared Function Min(ByVal ParamArray left() As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = (From r In left From p In r.Parameters Select p Distinct).ToArray()

        result.Generator = Expression.Call( _
           GetType(Enumerable), _
           "Min", _
           New Type() {GetType(Double)}, _
           Expression.NewArrayInit( _
              GetType(Double), _
              left.Select(Function(e) e.Generator)))

        Return result
    End Function

    Public Shared Function Choose(ByVal condition As RandomValue, ByVal left As RandomValue, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = Enumerable.Union(Enumerable.Union(left.Parameters, right.Parameters), condition.Parameters)
        If condition.Generator.NodeType = ExpressionType.Constant Then

            Dim v = CDbl(CType(condition.Generator, ConstantExpression).Value)

            If v > 0.0 Then
                result.Generator = left.Generator
            Else
                result.Generator = right.Generator
            End If
        Else
            result.Generator = Expression.Condition( _
             ToBoolean(condition.Generator), _
               left.Generator, _
               right.Generator)
        End If

        Return result
    End Function
    Public Shared Function Choose(ByVal condition As RandomValue, ByVal ParamArray left() As RandomValue) As RandomValue
        If left.Length = 2 Then
            Return Choose(condition, left(0), left(1))
        End If
        Dim result As New RandomValue(False)
        If left.Length = 0 Then
            Throw New Exception()
        End If
        If left.Length = 1 Then
            result.Generator = left(0).Generator
            result.Parameters = left(0).Parameters.ToArray()
        Else
            Dim q = From r In left From p In r.Parameters Select p
            result.Parameters = Enumerable.Union(q, condition.Parameters)

            result.Generator = Expression.ArrayAccess( _
               Expression.NewArrayInit( _
               GetType(Double), _
               left.Select(Function(e) e.Generator)), _
               Expression.Convert(condition.Generator, GetType(Int32)))
        End If

        Return result
    End Function

    Private Shared Function ValueExpr(ByVal rv As RandomValue) As expression

    End Function

    Private Shared Function ToDouble(ByVal expr As Expression) As expression
        If expr.Type Is GetType(Double) Then Return expr
        Return Expression.Condition( _
                 expr, _
                 Expression.Constant(1.0), _
                 Expression.Constant(0.0))
    End Function
    Private Shared Function ToBoolean(ByVal expr As Expression) As expression
        If expr.Type Is GetType(Boolean) Then Return expr
        Return Expression.GreaterThan( _
                 expr, _
                 Expression.Constant(0.0))
    End Function


#Region "right constant"
    Public Shared Operator +(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Add(left.Generator, Expression.Constant(right))
        Return result
    End Operator
    Public Shared Operator -(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Subtract(left.Generator, Expression.Constant(right))
        Return result
    End Operator
    Public Shared Operator *(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Multiply(left.Generator, Expression.Constant(right))
        Return result
    End Operator
    Public Shared Operator /(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Divide(left.Generator, Expression.Constant(right))
        Return result
    End Operator

    Public Shared Operator >(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.GreaterThan(left.Generator, Expression.Constant(right)), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator >=(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.GreaterThanOrEqual(left.Generator, Expression.Constant(right)), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator <(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.LessThan(left.Generator, Expression.Constant(right)), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator <=(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.LessThanOrEqual(left.Generator, Expression.Constant(right)), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator

    Public Shared Operator =(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.Equal(left.Generator, Expression.Constant(right)), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator <>(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.NotEqual(left.Generator, Expression.Constant(right)), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator

    Public Shared Operator And(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()

        If left.Generator.NodeType = ExpressionType.Constant Then
            Dim v = CDbl(CType(left.Generator, ConstantExpression).Value)

            If v > 0.0 Then
                result.Generator = If(right > 0.0, Expression.Constant(1.0), Expression.Constant(0.0))
            Else
                result.Generator = Expression.Constant(0.0)
            End If
        Else
            If right > 0.0 Then
                result.Generator = Expression.Condition( _
                    Expression.GreaterThan(left.Generator, Expression.Constant(0.0)), _
                    Expression.Constant(1.0), Expression.Constant(0.0))
            Else
                result.Generator = Expression.Constant(0.0)
            End If
        End If


        Return result
    End Operator
    Public Shared Operator Or(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()

        If left.Generator.NodeType = ExpressionType.Constant Then
            Dim v = CDbl(CType(left.Generator, ConstantExpression).Value)

            If v > 0.0 Then
                result.Generator = Expression.Constant(1.0)
            Else
                result.Generator = If(right > 0.0, Expression.Constant(1.0), Expression.Constant(0.0))
            End If
        Else
            If right > 0.0 Then
                result.Generator = Expression.Constant(1.0)
            Else
                result.Generator = Expression.Condition( _
                    Expression.GreaterThan(left.Generator, Expression.Constant(0.0)), _
                    Expression.Constant(1.0), Expression.Constant(0.0))
            End If
        End If
        Return result
    End Operator
    Public Shared Operator Mod(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "IEEERemainder", _
             Nothing, _
             left.Generator, Expression.Constant(right))
        Return result
    End Operator
    Public Shared Operator ^(ByVal left As RandomValue, ByVal right As Double) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = left.Parameters.ToArray()
        result.Generator = Expression.Power(left.Generator, Expression.Constant(right))
        Return result
    End Operator

#End Region

#Region "left constant"
    Public Shared Operator +(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Add(Expression.Constant(left), right.Generator)
        Return result
    End Operator
    Public Shared Operator -(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Subtract(Expression.Constant(left), right.Generator)
        Return result
    End Operator
    Public Shared Operator *(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Multiply(Expression.Constant(left), right.Generator)
        Return result
    End Operator
    Public Shared Operator /(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Divide(Expression.Constant(left), right.Generator)
        Return result
    End Operator

    Public Shared Operator >(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.GreaterThan(Expression.Constant(left), right.Generator), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator >=(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.GreaterThanOrEqual(Expression.Constant(left), right.Generator), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator <(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.LessThan(Expression.Constant(left), right.Generator), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator <=(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.LessThanOrEqual(Expression.Constant(left), right.Generator), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator

    Public Shared Operator =(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.Equal(Expression.Constant(left), right.Generator), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator
    Public Shared Operator <>(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Condition( _
           Expression.NotEqual(Expression.Constant(left), right.Generator), _
           Expression.Constant(1.0), _
           Expression.Constant(0.0))
        Return result
    End Operator

    Public Shared Operator And(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        If right.Generator.NodeType = ExpressionType.Constant Then
            Dim v = CDbl(CType(right.Generator, ConstantExpression).Value)

            If v > 0.0 Then
                result.Generator = If(left > 0.0, Expression.Constant(1.0), Expression.Constant(0.0))
            Else
                result.Generator = Expression.Constant(0.0)
            End If
        Else
            If left > 0.0 Then
                result.Generator = Expression.Condition( _
                    Expression.GreaterThan(right.Generator, Expression.Constant(0.0)), _
                    Expression.Constant(1.0), Expression.Constant(0.0))
            Else
                result.Generator = Expression.Constant(0.0)
            End If
        End If
        Return result
    End Operator
    Public Shared Operator Or(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        If right.Generator.NodeType = ExpressionType.Constant Then
            Dim v = CDbl(CType(right.Generator, ConstantExpression).Value)

            If v > 0.0 Then
                result.Generator = Expression.Constant(1.0)
            Else
                result.Generator = If(left > 0.0, Expression.Constant(1.0), Expression.Constant(0.0))
            End If
        Else
            If left > 0.0 Then
                result.Generator = Expression.Constant(1.0)
            Else
                result.Generator = Expression.Condition( _
                    Expression.GreaterThan(right.Generator, Expression.Constant(0.0)), _
                    Expression.Constant(1.0), Expression.Constant(0.0))
            End If
        End If
        Return result
    End Operator
    Public Shared Operator Mod(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Call( _
            GetType(Math), _
             "IEEERemainder", _
             Nothing, _
             Expression.Constant(left), right.Generator)
        Return result
    End Operator
    Public Shared Operator ^(ByVal left As Double, ByVal right As RandomValue) As RandomValue
        Dim result As New RandomValue(False)
        result.Parameters = right.Parameters.ToArray()
        result.Generator = Expression.Power(Expression.Constant(left), right.Generator)
        Return result
    End Operator

#End Region


    Public Overrides Function ToString() As String
        Dim meth = Expression.GetDelegateType( _
            Parameters.Select(Function(e) e.Type).ToArray())

        Dim ts = New List(Of String)
        For Each p In Parameters
            ts.Add(p.Type.Name)
        Next

        Dim signature = "Double Generate(" & String.Join(", ", ts.ToArray()) & ")"

        Dim srt = signature & vbCrLf & "{" & vbCrLf & _
                   "   return " & Generator.ToString() & vbCrLf & "}"

        Return srt
    End Function
End Class